package com.github.data_manage.controller

import cn.idev.excel.EasyExcel
import cn.idev.excel.support.ExcelTypeEnum
import com.github.data_manage.common.CommonPage
import com.github.data_manage.common.CommonResult
import com.github.data_manage.common.CompaniesEnum
import com.github.data_manage.common.ResultCode
import com.github.data_manage.config.SystemException
import com.github.data_manage.dao.*
import com.github.data_manage.domain.po.Company
import com.github.data_manage.domain.po.Persons
import com.github.data_manage.domain.vo.CompaniesPageParam
import com.github.data_manage.domain.vo.CompanyMergeVo
import com.github.data_manage.enum.SortType
import com.github.data_manage.util.PageUtil
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletResponse
import jakarta.transaction.Transactional
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.domain.Specification
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.util.StringUtils
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.net.URLEncoder
import java.nio.charset.StandardCharsets


/**
 *@author CHN
 *@since 2024-08-07 22:07
 */
@RestController
@Tag(name = "CompaniesController", description = "公司管理")
@RequestMapping("/companies")
class CompanyController : BaseController<Company>() {

    @Autowired
    lateinit var companyDao: CompanyDao

    @Autowired
    lateinit var companyShareholderDao: CompanyShareholderDao

    @Autowired
    lateinit var personsDao: PersonsDao

    @Autowired
    lateinit var fundDao: FundDao

    @Autowired
    lateinit var personWorkExperienceDao: PersonWorkExperienceDao

    @Operation(description = "新增/编辑公司")
    @RequestMapping(value = ["/saveOrUpdate"], method = [RequestMethod.POST])
    @Transactional(rollbackOn = [Exception::class])
    fun saveOrUpdateCompany(@Validated @RequestBody company: Company): CommonResult<String?> {
        if (!StringUtils.hasText(company.companyName)) {
            return CommonResult.failed("公司名字不能为空")
        }
        // 修改
        if (company.companyId != null) {
            companyDao.findById(company.companyId!!).orElseThrow { SystemException("更新的公司不存在") }
        } else {
            // 新增,保证公司名字不能重复
            if (companyDao.countCompanyByName(company.companyName!!) > 0) {
                throw SystemException("公司${company.companyName}已存在")
            }
        }
        companyDao.save(company)
        fundDao.updateCompanyNameByCompanyId(company.companyId!!, company.companyName!!, company.companyAddress)
        personWorkExperienceDao.updateCompanyNameByCompanyId(company.companyId!!, company.companyName!!)
        personsDao.updateCurrentCompanyNameByCompanyId(company.companyId!!, company.companyName!!)
        companyShareholderDao.removeAllByCompanyIdEquals(company.companyId!!)
        company.companyShareholders?.forEach { companyShareholder ->
            if (companyShareholder.personId == null) {
                val persons = Persons()
                persons.name = companyShareholder.name
                persons.currentCompanyId = company.companyId
                persons.currentCompany = company.companyName
                personsDao.save(persons)
                companyShareholder.personId = persons.personId
            }
            companyShareholder.companyId = company.companyId
            companyShareholder.id = null
            companyShareholderDao.save(companyShareholder)
        }
        return CommonResult.success(ResultCode.SUCCESS.message)
    }

    @Operation(description = "公司信息详情")
    @GetMapping(value = ["/details"])
    fun getCompanyDetailsById(@RequestParam companyId: Int): CommonResult<Company> {
        companyDao.findById(companyId)
            .map { company ->
                company.companyShareholders = companyShareholderDao.findAllByCompanyIdEquals(companyId)
                CommonResult.success(company)
            }.orElse(CommonResult.failed(CompaniesEnum.NO_DATA.message))
        return CommonResult.success(companyDao.findById(companyId).get())
    }

    @Operation(description = "删除公司")
    @DeleteMapping(value = ["/delete"])
    @Transactional(rollbackOn = [Exception::class])
    fun deleteCompanyById(@RequestBody companyIds: Collection<Int>): CommonResult<String> {
        companyDao.deleteAllById(companyIds)
        return CommonResult.success(CompaniesEnum.DELETE_SUCCESS.message);
    }

    @Operation(description = "公司列表")
    @RequestMapping(value = ["/list"], method = [RequestMethod.POST])
    @ResponseBody
    fun getCompanyList(@Validated @RequestBody companiesPageParam: CompaniesPageParam): CommonResult<CommonPage<Company>> {
        val condition = Specification<Company> { root, _, builder ->
            if (StringUtils.hasText(companiesPageParam.companyName)) {
                return@Specification builder.like(
                    root.get<String>("companyName"),
                    "%${companiesPageParam.companyName}%"
                )
            }
            return@Specification builder.isNotNull(root.get<Int>("companyId"))
        }
        val page = PageUtil.buildJpaPage<Company>(companiesPageParam.pageNum, companiesPageParam.pageSize)
            .let {
                if (companiesPageParam.sort != null) {
                    when (companiesPageParam.sort!!.sortType) {
                        SortType.DESC -> it.withSort(Sort.by(companiesPageParam.sort!!.field).descending())
                        SortType.ASC -> it.withSort(Sort.by(companiesPageParam.sort!!.field).ascending())
                    }

                } else {
                    it.withSort(Sort.by("createTime").descending())
                }
            }

        return CommonResult.success(
            CommonPage.restPage(companyDao.findAll(condition, page))
                .mapAsync { company ->
                    company.companyShareholders = companyShareholderDao.findAllByCompanyIdEquals(company.companyId!!)
                    company
                })
    }


    @GetMapping("/importTemplate")
    @Operation(description = "导入模板下载")
    fun getImportTemplate(response: HttpServletResponse) {
        response.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
        response.characterEncoding = StandardCharsets.UTF_8.name()
        response.setHeader(
            HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(
                "公司信息导入.xlsx", StandardCharsets.UTF_8
            )
        )
        response.outputStream.use { fos ->
            EasyExcel.write(fos, Company::class.java)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet("模板")
                .doWrite {
                    emptyList<Company>()
                }
        }
    }


    @PostMapping("/importTemplate")
    @Operation(description = "模板导入")
    @Transactional(rollbackOn = [Exception::class])
    fun importTemplate(@RequestParam("excelFile") excelFile: MultipartFile): CommonResult<String> {
        excelFile.inputStream.use { fis ->
            EasyExcel.read(fis)
                .head(Company::class.java)
                .doReadAllSync<Company>()
                .forEach { company ->
                    if (companyDao.findCompanyByCompanyNameEquals(company.companyName!!) == null) {
                        companyDao.save(company)
                    }
                }
        }
        return CommonResult.success(ResultCode.SUCCESS.message);
    }

    @PostMapping("/merge")
    @Operation(description = "公司合并")
    @Transactional(rollbackOn = [Exception::class])
    fun companyMerge(@Validated @RequestBody companyMergeVo: CompanyMergeVo): CommonResult<Boolean> {
        val dbMainCompany =
            companyDao.findCompanyByCompanyNameEquals(companyMergeVo.mainCompany.companyName!!)
                ?: throw SystemException("待合并的公司信息不存在")
        val minorCompanyId = companyMergeVo.minorCompanyIds.toMutableSet().let {
            it.remove(dbMainCompany.companyId)
            it.first()
        }

        companyDao.findById(minorCompanyId)
            .orElseThrow { throw SystemException("待合并的公司信息不存在") }
        companyDao.deleteById(minorCompanyId)
        companyMergeVo.mainCompany.companyId = dbMainCompany.companyId
        companyDao.save(companyMergeVo.mainCompany)
        companyShareholderDao.removeAllByCompanyIdEquals(companyMergeVo.mainCompany.companyId!!)
        companyShareholderDao.removeAllByCompanyIdEquals(minorCompanyId)
        companyMergeVo.mainCompany.companyShareholders?.forEach { companyShareholder ->
            if (companyShareholder.personId == null) {
                val persons = Persons()
                persons.name = companyShareholder.name
                persons.currentCompanyId = companyMergeVo.mainCompany.companyId
                persons.currentCompany = companyMergeVo.mainCompany.companyName
                personsDao.save(persons)
                companyShareholder.personId = persons.personId
            }
            companyShareholder.companyId = companyMergeVo.mainCompany.companyId
            companyShareholder.id = null
            companyShareholderDao.save(companyShareholder)
        }
        personWorkExperienceDao.mergeCompany(
            companyMergeVo.mainCompany.companyId!!,
            companyMergeVo.mainCompany.companyName!!,
            minorCompanyId
        )

        fundDao.mergeCompany(
            companyMergeVo.mainCompany.companyId!!,
            companyMergeVo.mainCompany.companyName!!,
            minorCompanyId
        )
        return CommonResult.success(true)
    }
}
